package com.shuiyun.jtt.handler;

import cn.hutool.core.util.ObjectUtil;
import com.shuiyun.jtt.enums.JT808;
import com.shuiyun.jtt.message.JTMessage;
import com.shuiyun.jtt.session.Session;
import com.shuiyun.jtt.session.SessionManager;
import com.shuiyun.jtt.utils.CacheKey;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;

/**
 * @author shuiyun
 * @description 交通部消息处理器
 * @date 2022-04-19 23:22
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class JTMessageHandler extends SimpleChannelInboundHandler<JTMessage> {

    private final List<Integer> accessMessageIds = Arrays.asList(JT808.终端注册0x0100,JT808.终端鉴权0x0102);

    private final SessionManager sessionManager;
    private final ApplicationContext context;

    public JTMessageHandler(SessionManager sessionManager, ApplicationContext context) {
        this.sessionManager = sessionManager;
        this.context = context;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, JTMessage msg) throws Exception {
        Channel channel = ctx.channel();
        Integer messageType = msg.getMessageType();
        Session session = channel.attr(Session.KEY).get();
        Handler handler = CacheKey.instance.getHandlerMap().get(messageType);
        // 判断当前方法是否有返回值 如果无返回值 则返回通用应答 如果有返回值 则返回返回值
        if (ObjectUtil.isNull(handler)){
            log.error("未知的消息类型：{}",messageType);
            return;
        }
        // 如果当前消息不是注册和鉴权 则需要校验当前消息是否是已经注册的设备 不接受未注册的设备的消息
        if (!accessMessageIds.contains(messageType)){
            Session tempSession = sessionManager.get(msg.getHeader().getClientId());
            if (ObjectUtil.isNull(tempSession)){
                log.error("不接收未注册设备的消息：{}",session);
                ctx.channel().close();
            }
        }

        if (handler.returnVoid){
            handler.invoke(msg, session,context);
        }else{
            JTMessage response = handler.invoke(msg, session,context);
            channel.writeAndFlush(response);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        Session session = sessionManager.newSession(channel);
        channel.attr(Session.KEY).set(session);
        log.error(">>>>>终端连接{}", session);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Session session = ctx.channel().attr(Session.KEY).get();
        session.invalidate();
        log.error("<<<<<断开连接{}", session);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            IdleState state = event.state();
            if (state == IdleState.READER_IDLE || state == IdleState.WRITER_IDLE) {
                Session session = ctx.channel().attr(Session.KEY).get();
                log.error("<<<<<终端主动断开连接{}", session);
                ctx.close();
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable e) throws Exception {
        Session session = ctx.channel().attr(Session.KEY).get();
        log.error("<<<<<消息处理异常{}", session, e);
    }
}
